//-----------------------------------------------------------------------
// <copyright file="Sync.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// </copyright>
// <author>Giles Knap [Updated 03 Apr 08: Mike Fourie - Code Cleanup, TFS 2008 Support, Workingdirectory Support etc.]</author>
// <date>2006-03-23</date>
// <summary>Syncs with SourceTfs</summary>
//-----------------------------------------------------------------------

namespace Microsoft.Sdc.Tasks.SourceTfs
{
    using System.Text;
    using System.Globalization;
    using System.IO;
    using Microsoft.Sdc.Tasks.Configuration;
    using Microsoft.Build.Framework;

    /// <summary>
    /// Syncronises with SourceTfs.
    /// </summary>
    /// <remarks>
    /// <code><![CDATA[<SourceTfs.Sync OutputFolder="outputFolder" Label="label" All="all" Overwrite="overwrite" Force="force" TfsVersion="tfsVersion" WorkingDirectory="workingDirectory"/>]]></code>
    /// <para>where:</para>
    /// <para><i>outputFolder</i></para>
    /// <para>The path to the folder to write the sync command output to. If not specified it won't be written to a file.</para>
    /// <para><i>label</i></para>
    /// <para>If specified syncs to the label.</para>
    /// <para><i>all</i></para>
    /// <para>If specified forces all files to be retrieved, not just those that are out-of-date.</para>
    /// <para><i>overwrite</i></para>
    /// <para>If specified overwrites writable files that are not checked out.</para>
    /// <para><i>force</i></para>
    /// <para>If specified implies <i>all</i> and <i>overwrite.</i></para>
    /// <para><i>tfsVersion</i></para>
    /// <para>Version of TFS to use. Supports 2005 and 2008. Default is 2005</para>
    /// <para><i>workingDirectory</i></para>
    /// <para>Specifies the WorkingDirectory to run TF.exe in. This determines the workspace</para>
    /// </remarks>
    /// <example>
    /// <code><![CDATA[
    /// <Project>
    ///     <Target Name="Test" >
    ///         <SourceTfs.Sync
    ///             OutputFolder="c:\temp"
    ///             Label="ConfigMainLatest" />
    ///     </Target>
    /// </Project>
    /// ]]></code>    
    /// </example>
    public class Sync : TaskBase
    {
        /// <summary>
        /// If specified forces all files to be retrieved, not just those that are out-of-date.
        /// </summary>
        private bool all = false;

        /// <summary>
        /// If specified implies <i>all</i> and <i>overwrite.</i>
        /// </summary>
        private bool force = false;

        /// <summary>
        /// If specified syncs to the label.
        /// </summary>
        private string label;

        /// <summary>
        /// The path to the folder to write the sync command output to. If not specified it won't be written to a file.
        /// </summary>
        private string outputFolder;

        /// <summary>
        /// If specified overwrites writable files that are not checked out.
        /// </summary>
        private bool overwrite = false;

        /// <summary>
        /// Specifies the path to the file or folder.
        /// </summary>
        private string path = ""; // default to the whole depot
        private string tfsVersion = "2005";
        private string workingDirectory;

        /// <summary>
        /// Gets or sets the working directory.
        /// </summary>
        /// <value>The working directory.</value>
        public string WorkingDirectory
        {
            get { return this.workingDirectory; }
            set { this.workingDirectory = value; }
        }

        /// <summary>
        /// Gets or sets the TFS version.
        /// </summary>
        /// <value>The TFS version.</value>
        public string TfsVersion
        {
            get { return this.tfsVersion; }
            set { this.tfsVersion = value; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether to force all files to be retrieved, not just those that are out-of-date.
        /// </summary>
        public bool All
        {
            get { return this.all; }
            set { this.all = value; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether to imply <i>all</i> and <i>overwrite.</i>
        /// </summary>
        public bool Force
        {
            get { return this.force; }
            set { this.force = value; }
        }

        /// <summary>
        /// Gets or sets the label with which to synchronize
        /// </summary>
        /// <value>Label name</value>
        public string Label
        {
            get { return this.label; }
            set { this.label = value; }
        }

        /// <summary>
        /// Gets or sets If specified the sync output will be written to this file
        /// </summary>
        public string OutputFolder
        {
            get { return this.outputFolder; }
            set { this.outputFolder = value; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether to overwrite writable files that are not checked out.
        /// </summary>
        public bool Overwrite
        {
            get { return this.overwrite; }
            set { this.overwrite = value; }
        }

        /// <summary>
        /// Gets or sets the path to the file or folder.
        /// </summary>
        /// <value>The full path to the file or folder.</value>
        public string Path
        {
            get { return this.path; }
            set { this.path = value; }
        }

        /// <summary>
        /// Performs the action of this task.
        /// </summary>
        protected override void InternalExecute()
        {
            ShellExecute shellExecute = new ShellExecute();
            Helper h = new Helper(this.TfsVersion);
            shellExecute.Filename = h.TfExePath;
            if (string.IsNullOrEmpty(this.WorkingDirectory) == false)
            {
                shellExecute.WorkingDirectory = this.WorkingDirectory;
            }

            string outputFilePath = null;

            if (this.OutputFolder.Length > 0)
            {
                outputFilePath = System.IO.Path.Combine(this.OutputFolder, "SourceTfsSync.txt");

                if (!Directory.Exists(this.OutputFolder))
                {
                    Directory.CreateDirectory(this.outputFolder);
                }

                if (System.IO.File.Exists(outputFilePath))
                {
                    System.IO.File.Delete(outputFilePath);
                }
            }

            StringBuilder args = new StringBuilder();
            args.AppendFormat(CultureInfo.InvariantCulture, "Get \"{0}\" /noprompt /recursive", this.path);
            if (this.all)
            {
                args.Append(" /all");
            }

            if (this.force)
            {
                args.Append(" /force");
            }

            if (this.label != null && this.label.Length > 0)
            {
                args.AppendFormat(CultureInfo.InvariantCulture, " /version:L{0}", this.label);
            }

            if (this.overwrite)
            {
                args.Append(" /overwrite");
            }

            Log.LogMessageFromResources("SourceTfs.Sync");
            shellExecute.Arguments = args.ToString();
            Log.LogMessage(MessageImportance.Normal, string.Format("Executing {0} with {1}", shellExecute.Filename, args));
            int returnValue = shellExecute.Execute();

            // stdOut contains a list of files synced
            if (this.OutputFolder.Length > 0)
            {
                StreamWriter sw = System.IO.File.CreateText(outputFilePath);
                sw.Write(shellExecute.StandardOutput);
                sw.Close();
            }

            Log.LogMessage(MessageImportance.Low, shellExecute.StandardOutput);
            switch (returnValue)
            {
                case 1:
                    Log.LogWarning("Exit Code 1. Partial success: " + shellExecute.StandardError.Trim());
                    break;
                case 2:
                    Log.LogError("Exit Code 2. Unrecognized command: " + shellExecute.StandardError.Trim());
                    break;
                case 100:
                    Log.LogError("Exit Code 100. Nothing Succeeded: " + shellExecute.StandardError.Trim());
                    break;
            }
        }
    }
}